﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Linq;
using System.Security.Permissions;
using System.Web.UI;
using System.Web.UI.WebControls;
using Medianamik.Core;
using Medianamik.Core.Configuration;
using Medianamik.Core.Interfaces;
using Medianamik.Core.Security;
using Medianamik.Globalization;
using Medianamik.UI.Controls;
using Telerik.Web.UI;

namespace Medianamik.UI.ContentManagement
{
    /// <summary>
    /// On doit recevoir soit le param nodeid (Édition)ou le param typeid (Création) 
    /// Le param parentnodeid est optionnel (Création)
    /// </summary>
    public partial class NodeManagement : BaseModuleEditionPage<NodeWrapper>
    {
        bool _lockFailed;

        protected void Page_Load(object sender, EventArgs e)
        {
            bctFilAriane.NavigateParent += bctFilAriane_NavigateParent;
            Core.Sugar.Resources.RegisterScript("Lock.lockRequester.js",
                    Page, typeof(LockButton).Assembly);

            if (IsPostBack)
            {
                //Un noeud de l'abre "ne requérant pas de chargement des enfants" vient d'être sélectionné (NodeClick)
                if (!String.IsNullOrEmpty(Request[PostBack.PostBackEventTarget])
                    && !String.IsNullOrEmpty(Request[PostBack.PostBackEventArgument]))
                {
                    if (Request[PostBack.PostBackEventTarget].Equals(isNavigating.ClientID) ||
                        Request[PostBack.PostBackEventTarget].Contains(ControlIDs.BreadcrumbTrail))
                    {
                        AddHistoryPoint(Request[PostBack.PostBackEventArgument]);
                        NodeId = new Guid(Request[PostBack.PostBackEventArgument]);
                        GoToNodeId();
                        LoadBreadcrumbs();
                        if (IsBreadcrumbsEnabled()) breadcrumbUpdatePanel.Update();
                        RebindFields();
                    }
                    else if (Request[PostBack.PostBackEventTarget].Equals(lockResquestFailed.ClientID))
                    {
                        LockInfoTooltip.ObjectId = new Guid(Request[PostBack.PostBackEventArgument]);
                        LockInfoTooltip.DataBind();
                        LockInfoTooltip.Show();
                        _lockFailed = true;
                        GoToNodeId();
                    }
                    else if (Request[PostBack.PostBackEventTarget].Equals(backOrForward.ClientID))
                    {
                        NodeId = new Guid(Request[PostBack.PostBackEventArgument]);
                        GoToNodeId();
                        LoadBreadcrumbs();
                        if (IsBreadcrumbsEnabled()) breadcrumbUpdatePanel.Update();
                        RebindFields();
                    }
                }
            }
            else
            {
                if (!Roles.UserHasRight(CurrentNode, SecurityLevels.Update))
                    Response.Redirect("/medianamik/Unauthorized.aspx");

                btnRevert.Attributes.Add("onclick", "return confirm('" + Translator.TranslateJS("Medianamik_ContentManagement", "ConfirmRevert") + "');");

                if (Request.QueryString.AllKeys.Any(k => k.ToLower() == DefaultParamNames.HideTreeview))
                {
                    TreeviewPlaceholder.Visible = false;
                }
                else
                {
                    LoadRootNodes();
                }

                LoadBreadcrumbs();
                btnRevert.Visible = IsEdition && CurrentNode.IsDraft
                    && !Revision.HasValue
                    && CurrentNode.DefaultInstance.Revisions.Length > 0;
                lnkCancel.HRef = ReturnURL;
            }

            DisplayPublishOrApprove();
        }

        private void DisplayPublishOrApprove()
        {
            SaveAndPublishLoginView.Visible = Roles.UserCanPublish(CurrentNode.InnerNode);
            SaveAndApprovePlaceHolder.Visible = Roles.UserCanApprove(CurrentNode.InnerNode);
        }

        protected void LockInfoTooltip_LockDeleted(object sender, EventArgs e)
        {
            ReloadTree();
            LoadBreadcrumbs();
            if (IsBreadcrumbsEnabled()) breadcrumbUpdatePanel.Update();
        }

        protected void btnRevert_Click(object sender, EventArgs e)
        {
            NodeManager.RevertNode(NodeId, CurrentEditionCulture);
            Response.Redirect(ReturnURL);
        }

        [PrincipalPermission(SecurityAction.Assert, Role = "PublishContent")]
        protected void btnSaveAndPublish_Click(object sender, EventArgs e)
        {
            base.SaveAndPublish(sender, e);
        }

        protected void btnSaveAndApprove_Click(object sender, EventArgs e)
        {
            base.SaveAndApprove();
        }

        internal virtual void RedirectTo(string url)
        {
            Response.Redirect(url);
        }

        internal virtual NodeWrapper GetUpdatedNode()
        {
            return MedianamikFormTemplate.GetFormValue(CurrentNode);
        }

        protected override void OnCultureChanged(CultureChangedEventArgs e)
        {
            ReloadTree();
            LoadBreadcrumbs();
            if (IsBreadcrumbsEnabled())
                breadcrumbUpdatePanel.Update();

            base.OnCultureChanged(e);
        }

        protected void OnNavigate(object sender, HistoryEventArgs e)
        {
            if (MyScriptManager.IsNavigating)
            {
                string nodeID = e.State.Get("NodeId");

                string script;

                if (String.IsNullOrEmpty(nodeID))
                {
                    nodeID = RootNodeId.ToString();
                }

                if (nodeID == RootNodeId.ToString())
                {
                    script = String.Format("confirmLeaveEdition('{0}');", nodeID);
                }
                else
                {
                    script = String.Format("if (confirm('{3}')) {{ $find('{4}').tryLock('{0}', 3600, function() {{ OnNavigate('{0}', '{1}'); }}, function() {{ __doPostBack('{2}', '{0}'); }});}}"
                        , nodeID
                        , backOrForward.ClientID
                        , lockResquestFailed.ClientID
                        , Translator.Translate("Medianamik_ContentManagement", "SwitchNodeEditionMessage")
                        , MedianamikFormTemplate.LockRequester.ClientID);
                }

                ScriptManager.RegisterStartupScript(this, typeof(NodeManagement), "backOrForwardScript", script, true);
            }
        }

        private bool IsBreadcrumbsEnabled()
        {
            return CurrentNode.NodeType.GetAllProperties().Any(p => p.Name.EqualsIgnoreCase("Name"));
        }

        void bctFilAriane_NavigateParent(object sender, NavigateParentEventArgs e)
        {
            NodeId = new Guid(e.ItemID);
            GoToNodeId();
            LoadBreadcrumbs();
            RebindFields();
        }

        protected void NodeExpand(object sender, RadTreeNodeEventArgs e)
        {
            if (!_lockFailed)
            {
                if (String.IsNullOrEmpty(isNavigating.Value))
                {
                    ExpandNode(e.Node, false);
                }
                else
                {
                    NodeId = new Guid(isNavigating.Value);
                    AddHistoryPoint(isNavigating.Value);
                    isNavigating.Value = "";
                    ExpandNode(e.Node, true);
                    LoadBreadcrumbs();
                    if (IsBreadcrumbsEnabled()) breadcrumbUpdatePanel.Update();
                    RebindFields();
                }
            }
        }

        private List<Node> _childNodes;
        public List<Node> ChildNodes
        {
            get
            {
                if (_childNodes == null)
                {
                    _childNodes = CurrentNode.GetChildContentNodes(CurrentEditionCulture).Where(n => !n.NodeType.IsSystem).ToList();
                }
                return _childNodes;
            }
        }

        public override LinkButton SaveButton
        {
            get { return btnSave; }
        }

        public override MedianamikFormTemplate MedianamikFormTemplate
        {
            get
            {
                return nodeFields;
            }
        }

        protected override string ReturnURL
        {
            get
            {
                if (string.IsNullOrEmpty(Request.QueryString[DefaultParamNames.ReturnURL]))
                {
                    //par defaut on retourne à NodeList 
                    var returnURL = "NodeList.aspx";

                    if (CurrentNode.ParentID.HasValue)
                        returnURL += String.Format("?{0}={1}", DefaultParamNames.ParentNodeID, CurrentNode.ParentID.Value);
                    return returnURL;
                }

                return base.ReturnURL;
            }
        }

        //protected override string NodeIdParamName
        //{
        //    get
        //    {
        //        return "nodeid";
        //    }
        //}

        protected override string ParentNodeIdParamName
        {
            get
            {
                return DefaultParamNames.ParentNodeID;
            }
        }

        protected Guid RootNodeId
        {
            get { return MedianamikModules.ContentManagement; }
        }

        public override UpdatePanel FieldsPanel
        {
            get
            {
                return fieldsPanel;
            }
        }

        public void ReloadTree()
        {
            if (TreeviewPlaceholder.Visible)
            {
                treeview.Nodes.Clear();
                GoToNodeId();
            }
        }

        private void ExpandNode(RadTreeNode node, bool selected)
        {
            ExpandNode(node, selected, null);
        }

        private void ExpandNode(RadTreeNode node, bool selected, INode rootNode)
        {
            if (node == null) { return; }
            if (selected)
            {
                treeview.ClearSelectedNodes();
                //treeview.CollapseAllNodes();
            }

            if (node.ExpandMode == TreeNodeExpandMode.ServerSide)
            {
                var parentNode = rootNode ?? NodeManager.GetNode(new Guid(node.Value));

                if (parentNode.ID == CurrentNode.ID)
                {
                    foreach (var item in ChildNodes)
                    {
                        var newNode = CreateTreeNode(item);

                        if (item.HasChildren)
                        {
                            newNode.ExpandMode = TreeNodeExpandMode.ServerSide;
                        }

                        node.Nodes.Add(newNode);
                    }
                }
                else
                {
                    foreach (var item in parentNode.GetChildContentNodes(CurrentEditionCulture).Where(n => !n.NodeType.IsSystem))
                    {
                        var newNode = CreateTreeNode(item);

                        if (item.HasChildren)
                        {
                            newNode.ExpandMode = TreeNodeExpandMode.ServerSide;
                        }

                        node.Nodes.Add(newNode);
                    }
                }

                node.ExpandMode = TreeNodeExpandMode.ClientSide;
            }

            node.Expanded = true;
            node.ExpandParentNodes();
            node.Selected = selected;
        }

        private void LoadRootNodes()
        {
            if (TreeviewPlaceholder.Visible)
            {
                var rootNode = NodeManager.GetNode(RootNodeId);
                var rootTreeNode = CreateTreeNode(rootNode);
                rootTreeNode.ExpandMode = TreeNodeExpandMode.ServerSide;
                treeview.Nodes.Add(rootTreeNode);
                ExpandNode(rootTreeNode, true, rootNode);
                if (CurrentNode.ID != RootNodeId)
                {
                    GoToNodeId();
                }
            }
        }

        private void GoToNodeId()
        {
            if (treeview.Nodes.Count < 1)
                LoadRootNodes();

            if (treeview.Nodes.Count > 0)
            {
                RadTreeNode selectedTreeNode = null;

                if (CurrentNode.Status == EntityStates.New)
                {
                    selectedTreeNode = CurrentNode.ParentID.HasValue ?
                        treeview.FindNodeByValue(CurrentNode.ParentID.ToString()) :
                        treeview.FindNodeByValue(RootNodeId.ToString());
                }
                else
                    selectedTreeNode = treeview.FindNodeByValue(NodeId.ToString());

                //Si le noeud n'est pas dans l'arbre
                if (selectedTreeNode == null)
                {
                    //Trouver le parent déjà dans l'arbre
                    IEnumerable<Guid> parentIDs = CurrentNode.GetParentIDs(true);
                    int i = 0;

                    while (selectedTreeNode == null && i < parentIDs.Count())
                    {
                        selectedTreeNode = treeview.FindNodeByValue(parentIDs.ElementAt(i).ToString());
                        i++;
                    }

                    if (selectedTreeNode != null)
                    {
                        //Expand parent node until SelectedNodeId reached
                        for (var j = i - 1; j >= 0; j--)
                        {
                            ExpandNode(selectedTreeNode, false);

                            if (j - 1 > 0)
                            {
                                selectedTreeNode = selectedTreeNode.Nodes
                                    .FindNodeByValue(parentIDs.ElementAt(j - 1).ToString());
                            }
                        }

                        selectedTreeNode = selectedTreeNode.Nodes.FindNodeByValue(NodeId.ToString());
                    }
                }

                if (selectedTreeNode == null && CurrentNode.Status == EntityStates.New && CurrentNode.ParentID.HasValue)
                {
                    selectedTreeNode = treeview.FindNodeByValue(CurrentNode.ParentID.ToString());
                }

                ExpandNode(selectedTreeNode, true, CurrentNode);
            }
        }

        private static RadTreeNode CreateTreeNode(INode node)
        {
            return new RadTreeNode
            {
                Text = node.DisplayName,
                Value = node.ID.ToString(),
                ImageUrl = node.NodeType.IconPath ?? String.Empty
            };
        }

        private void LoadBreadcrumbs()
        {
            if (IsBreadcrumbsEnabled())
            {
                bctFilAriane.Breadcrumbs = CurrentNode.Breadcrumbs;
                bctFilAriane.DataBind();
            }
        }

        private void AddHistoryPoint(string historyPoint)
        {
            var pageState = new NameValueCollection { { "NodeId", historyPoint } };
            MyScriptManager.AddHistoryPoint(pageState, Page.Title);
        }
    }
}